//****************************************Copyright (c)***********************************//
//Copyright(C) 写的bug都队 2023-2033
//All rights reserved                                  
//----------------------------------------------------------------------------------------
// File name:           rmii_tx
// Last modified Date:  2023/11/9
// Copy & modified:     写的bug都队
// Last Version:        V2.0
// Descriptions:        以太网物理层发送数据，并加入前导码和CRC
//----------------------------------------------------------------------------------------
// Author :             LAKKA
// Created date:        2023/06/05
//****************************************************************************************//

//*****************************************************
//**        以太网待发送数据: 8bit -> 2bit
//*****************************************************

module rmii_tx(
    input               clk         , 
    input               rst         ,
    input [7:0]         data        ,
    input               tx_en       ,
    output reg          tx_av       ,
    output reg          tx_bz       ,

    output reg [1:0]    p_txd       ,
    output reg          p_txen
);

//实现eth数据帧的封装传输

reg[7:0] buffer[2047:0];
reg[16:0] begin_ptr;
reg[16:0] end_ptr;
reg[7:0] buffer_out;

reg[7:0] send_status;

reg[7:0] tick;
reg[16:0] send_cnt;

reg int_en;


reg[31:0] crc;
wire [31:0] crc_next;

reg crc_ct;
reg [7:0] crc_in;

wire [7:0] data_i;

assign data_i = {crc_in[0],crc_in[1],crc_in[2],crc_in[3],crc_in[4],crc_in[5],crc_in[6],crc_in[7]};

assign crc_next[0] = crc[24] ^ crc[30] ^ data_i[0] ^ data_i[6];
assign crc_next[1] = crc[24] ^ crc[25] ^ crc[30] ^ crc[31] ^ data_i[0] ^ data_i[1] ^ data_i[6] ^ data_i[7];
assign crc_next[2] = crc[24] ^ crc[25] ^ crc[26] ^ crc[30] ^ crc[31] ^ data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[6] ^ data_i[7];
assign crc_next[3] = crc[25] ^ crc[26] ^ crc[27] ^ crc[31] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[7];
assign crc_next[4] = crc[24] ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ data_i[0] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[6];
assign crc_next[5] = crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data_i[0] ^ data_i[1] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^ data_i[6] ^ data_i[7];
assign crc_next[6] = crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ crc[31] ^ data_i[1] ^ data_i[2] ^ data_i[4] ^ data_i[5] ^ data_i[6] ^ data_i[7];
assign crc_next[7] = crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[31] ^ data_i[0] ^ data_i[2] ^ data_i[3] ^ data_i[5] ^ data_i[7];
assign crc_next[8] = crc[0] ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data_i[0] ^ data_i[1] ^ data_i[3] ^ data_i[4];
assign crc_next[9] = crc[1] ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ data_i[1] ^ data_i[2] ^ data_i[4] ^ data_i[5];
assign crc_next[10] = crc[2] ^ crc[24] ^ crc[26] ^ crc[27] ^ crc[29] ^ data_i[0] ^ data_i[2] ^ data_i[3] ^ data_i[5];
assign crc_next[11] = crc[3] ^ crc[24] ^ crc[25] ^ crc[27] ^ crc[28] ^ data_i[0] ^ data_i[1] ^ data_i[3] ^ data_i[4];
assign crc_next[12] = crc[4] ^ crc[24] ^ crc[25] ^ crc[26] ^ crc[28] ^ crc[29] ^ crc[30] ^ data_i[0] ^ data_i[1] ^ data_i[2] ^ data_i[4] ^ data_i[5] ^ data_i[6];
assign crc_next[13] = crc[5] ^ crc[25] ^ crc[26] ^ crc[27] ^ crc[29] ^ crc[30] ^ crc[31] ^ data_i[1] ^ data_i[2] ^ data_i[3] ^ data_i[5] ^ data_i[6] ^ data_i[7];
assign crc_next[14] = crc[6] ^ crc[26] ^ crc[27] ^ crc[28] ^ crc[30] ^ crc[31] ^ data_i[2] ^ data_i[3] ^ data_i[4] ^ data_i[6] ^ data_i[7];
assign crc_next[15] =  crc[7] ^ crc[27] ^ crc[28] ^ crc[29] ^ crc[31] ^ data_i[3] ^ data_i[4] ^ data_i[5] ^ data_i[7];
assign crc_next[16] = crc[8] ^ crc[24] ^ crc[28] ^ crc[29] ^ data_i[0] ^ data_i[4] ^ data_i[5];
assign crc_next[17] = crc[9] ^ crc[25] ^ crc[29] ^ crc[30] ^ data_i[1] ^ data_i[5] ^ data_i[6];
assign crc_next[18] = crc[10] ^ crc[26] ^ crc[30] ^ crc[31] ^ data_i[2] ^ data_i[6] ^ data_i[7];
assign crc_next[19] = crc[11] ^ crc[27] ^ crc[31] ^ data_i[3] ^ data_i[7];
assign crc_next[20] = crc[12] ^ crc[28] ^ data_i[4];
assign crc_next[21] = crc[13] ^ crc[29] ^ data_i[5];
assign crc_next[22] = crc[14] ^ crc[24] ^ data_i[0];
assign crc_next[23] = crc[15] ^ crc[24] ^ crc[25] ^ crc[30] ^ data_i[0] ^ data_i[1] ^ data_i[6];
assign crc_next[24] = crc[16] ^ crc[25] ^ crc[26] ^ crc[31] ^ data_i[1] ^ data_i[2] ^ data_i[7];
assign crc_next[25] = crc[17] ^ crc[26] ^ crc[27] ^ data_i[2] ^ data_i[3];
assign crc_next[26] = crc[18] ^ crc[24] ^ crc[27] ^ crc[28] ^ crc[30] ^ data_i[0] ^ data_i[3] ^ data_i[4] ^ data_i[6];
assign crc_next[27] = crc[19] ^ crc[25] ^ crc[28] ^ crc[29] ^ crc[31] ^ data_i[1] ^ data_i[4] ^ data_i[5] ^ data_i[7];
assign crc_next[28] = crc[20] ^ crc[26] ^ crc[29] ^ crc[30] ^ data_i[2] ^ data_i[5] ^ data_i[6];
assign crc_next[29] = crc[21] ^ crc[27] ^ crc[30] ^ crc[31] ^ data_i[3] ^ data_i[6] ^ data_i[7];
assign crc_next[30] = crc[22] ^ crc[28] ^ crc[31] ^ data_i[4] ^ data_i[7];
assign crc_next[31] = crc[23] ^ crc[29] ^ data_i[5];



reg [7:0] crc_buffer;





always @(*) begin
    //64 byte free
    tx_av <= (end_ptr + 2047 - begin_ptr)%2048 > 63;
    int_en <= tx_av && tx_en;
    if(crc_ct)
        crc_in <= buffer_out;
    else
        crc_in <= 8'b00000000;
    
    tx_bz <= send_status != 0;
end

//加前导码和CRC检验
always@(posedge clk or negedge rst)begin
    if(rst == 1'b0)begin
        begin_ptr <= 0;
        end_ptr <= 0;
        send_status <= 0;
    end else begin
        p_txen <= 1'b0;
        tick<=tick + 8'd1;
        if(tick == 3)begin
            tick <= 0;
        end
        if(int_en)begin
            buffer[begin_ptr] <= data;
            begin_ptr <= begin_ptr + 16'd1;
            if(begin_ptr == 2047)begin_ptr<=0;
        end
        case(send_status)
            0:begin //idle wait for tx_en
                if(begin_ptr != end_ptr)begin
                    send_status <= 1;
                    send_cnt <= 0;
                    crc<=32'hFFFFFFFF;
                end
            end
            1:begin //send preamble and SFD
                send_cnt <= send_cnt + 8'd1;
                p_txd <= 2'b01;
                p_txen <= 1'b1;
                if(send_cnt == 31)begin
                    p_txd <= 2'b11;
                    send_status <=2;
                    send_cnt <= 0;
                    tick <= 0;
                    crc_ct <= 1'b1;
                end
            end
            2:begin //send payload
                if(tick == 0)crc<=crc_next;

                buffer_out <= {2'bXX,buffer_out[7:2]};
                p_txd <= buffer_out[1:0];
                p_txen <= 1'b1;
                if(tick == 2)begin
                    end_ptr <= end_ptr + 16'd1;
                    if(end_ptr == 2047)end_ptr<=0;
                end

                if(tick == 3 && send_cnt < 96)send_cnt <= send_cnt + 8'd1;
                
                if(tick == 3 && (end_ptr - begin_ptr)%2048 == 0)begin
                    crc_ct <= 1'b0;
                    if(send_cnt < 63)
                        send_status <= 3;
                    else begin
                        send_status <= 4;
                        send_cnt <= 0;

                        crc_buffer <= ~{crc[24],crc[25],crc[26],crc[27],crc[28],crc[29],crc[30],crc[31]};
                        crc<={crc[23:0],8'hXX};
                    end
                end
            end
            3:begin //send padding
                if(tick == 0)crc <= crc_next;
                p_txd <= 0;
                p_txen <= 1'b1;
                if(tick == 3)begin
                    send_cnt <= send_cnt + 8'd1;
                    if(send_cnt == 63)begin
                        send_status <= 4;
                        send_cnt <= 0;

                        crc_buffer <= ~{crc[24],crc[25],crc[26],crc[27],crc[28],crc[29],crc[30],crc[31]};
                        crc<={crc[23:0],8'hXX};
                    end
                end
            end
            4:begin //send CRC  
                p_txd <= crc_buffer[1:0];
                crc_buffer <= {2'bXX,crc_buffer[7:2]};
                p_txen <= 1'b1;

                if(tick == 3)begin
                    crc_buffer <= ~{crc[24],crc[25],crc[26],crc[27],crc[28],crc[29],crc[30],crc[31]};
                    crc<={crc[23:0],8'hXX};

                    send_cnt <= send_cnt + 8'd1;
                    if(send_cnt == 3)begin
                        send_status <= 5;
                        send_cnt <= 0;
                    end
                end
            end
            5:begin //wait for 4 cycles
                p_txd <= 2'bXX;
                p_txen <= 1'b0;
                if(tick == 3)begin
                    send_status <= 0;
                end
            end
        endcase
        if(tick == 3)begin
            buffer_out <= buffer[end_ptr];
        end
    end

end


endmodule

